package com.netsdk.demo.customize;

import com.netsdk.demo.util.CaseMenu;
import com.netsdk.lib.NetSDKLib;
import com.netsdk.lib.ToolKits;
import com.netsdk.lib.enumeration.EM_PERSON_FEATURE_ERRCODE;
import com.netsdk.lib.enumeration.ENUMERROR;
import com.netsdk.lib.structure.*;
import com.netsdk.lib.utils.Initialization;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;

public class MultiFaceDemo extends Initialization {
    static NetSDKLib netsdkApi = NetSDKLib.NETSDK_INSTANCE;
    static NetSDKLib configApi = NetSDKLib.CONFIG_INSTANCE;
    private static NetSDKLib.LLong findHandle = new NetSDKLib.LLong(0);
    private static NetSDKLib.LLong attachFaceHandle = new NetSDKLib.LLong(0);
    private static int nToken;
    public class MultiFaceDetectState implements NetSDKLib.fMultiFaceDetectState{

        @Override
        public void invoke(NetSDKLib.LLong lAttachHandle, Pointer pstStates, Pointer dwUser) {
            //todo
        }
    }
//    private final NetSDKLib.fMultiFaceDetectStateEx = new

    public class IntPoint extends NetSDKLib.SdkStructure {

        public int value;

        public IntPoint() {
        }

        public IntPoint(int value) {
            this.value = value;
        }
    }

    /**
     * 以图搜图
     *
     * @param longHandle CLIENT_StartFindFaceRecognition 接口返回的查询句柄
     * @param count 查询的个数
     */
    public void doFindSearchByPictureEx(NetSDKLib.LLong longHandle, int count) {
        int doNextCount = 0;
        // 分页查找数据
        NET_IN_DOFIND_FACERECONGNITION_EX stFindIn =
                new NET_IN_DOFIND_FACERECONGNITION_EX();
        stFindIn.lFindHandle = longHandle;
        stFindIn.nCount = 10; // 当前想查询的记录条数
        stFindIn.nBeginNum = 0; // 每次递增

        NET_OUT_DOFIND_FACERECONGNITION_EX stFindOut =
                new NET_OUT_DOFIND_FACERECONGNITION_EX();
        stFindOut.nCadidateEx2Num = count;

//        stFindOut.bUseCandidatesEx = 1; // 是否使用候选对象扩展结构体
        NET_CANDIDATE_INFOEX2[] tmp = new NET_CANDIDATE_INFOEX2[count];
        for(int i = 0; i < count; i ++) {
            tmp[i] = new NET_CANDIDATE_INFOEX2();
        }
        stFindOut.nBufferLen = tmp[0].size()*count;
        stFindOut.pBuffer = new Memory(tmp[0].size() * count);
        stFindOut.pBuffer.clear(tmp[0].size() * count);
        for (int i = 0; i < count; i++) {
            tmp[i].stuCandidatesEx.stPersonInfo.szFacePicInfo[0].nFilePathLen = 256;
            tmp[i].stuCandidatesEx.stPersonInfo.szFacePicInfo[0].pszFilePath = new Memory(256);
        }
        stFindOut.pstuCandidatesEx2 = new Memory(tmp[0].size() * count);  // Pointer初始化
        stFindOut.pstuCandidatesEx2.clear(tmp[0].size() * count);

        ToolKits.SetStructArrToPointerData(tmp, stFindOut.pstuCandidatesEx2); // 将数组内存拷贝给 Pointer

        do {
            stFindIn.write();
            stFindOut.write();
            if (netsdkApi.CLIENT_DoFindFaceRecognitionEx(stFindIn.getPointer(), stFindOut.getPointer(), 1000)) {
                System.out.println(
                        "CLIENT_DoFindFaceRecognitionEx Succeed");
                stFindOut.read();
                ToolKits.GetPointerDataToStructArr(stFindOut.pstuCandidatesEx2, tmp);
                System.out.printf("Record Number [%d]\n", stFindOut.nRetCadidateEx2Num);

                if (stFindOut.nRetCadidateEx2Num == 0) {
                    System.out.println("没有查询到相关数据");
                    break;
                }
                for (int i = 0; i < stFindOut.nRetCadidateEx2Num; i++) {
                    int index = i + doNextCount * count; // 查询的总个数 - 1, 从0开始
                    // 建模状态
                    /** 0:未知 1:建模失败,可能是图片不符合要求,需要换图片 2:有可用的特征值 3:正在计算特征值 4:已建模，但算法升级导致数据不可用，需要重新建模 */
                    int status = tmp[i].stuCandidatesEx.stPersonInfo.emFeatureState;
                    System.out.println("建模状态: " + status);
                    // 如果建模失败,打印建模失败原因
                    if (status == 1) {
                        System.out.println(
                                "失败原因: "
                                        + EM_PERSON_FEATURE_ERRCODE.getErrorMessage(
                                        tmp[i].stuCandidatesEx.stPersonInfo.emFeatureErrCode));
                    }
                }
            } else {
                System.out.println(
                        "CLIENT_DoFindFaceRecognitionEx Failed, Error:" + ENUMERROR.getErrorMessage());
                break;
            }

            if (stFindOut.nRetCadidateEx2Num < stFindIn.nCount) {
                System.out.println("没有更多数据,结束查询");
                break;
            } else {
                stFindIn.nBeginNum += count;
                doNextCount++;
            }
        } while (true);
        netsdkApi.CLIENT_StopFindFaceRecognition(longHandle);
    }

    /**
     * 以图搜图
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param chn       通道号
     * @param similary  相似度
     * @param memory    图片缓存
     * @param nPicLen   图片大小
     */
    public void searchByPictureMultiVer(String startTime, String endTime, int chn, String similary, Memory memory, int nPicLen) {
        String[] startTimeStr = startTime.split("-");
        String[] endTimeStr = endTime.split("-");


        NET_IN_STARTMULTIFIND_FACERECONGNITION_EX stInStartFind = new NET_IN_STARTMULTIFIND_FACERECONGNITION_EX();

        // 通道号
        stInStartFind.nChannelCount = 5;
        IntPoint[] intPoints = new IntPoint[5];
        for (int i = 0; i < 5; i++) {
            intPoints[i] = new IntPoint(i);
        }
        stInStartFind.pChannelID = new Memory(intPoints[0].size() * stInStartFind.nChannelCount);
        stInStartFind.pChannelID.clear(intPoints[0].size() * stInStartFind.nChannelCount);
        ToolKits.SetStructArrToPointerData(intPoints, stInStartFind.pChannelID);
        stInStartFind.bPersonEx2Enable = 1;    // 人员信息查询条件是否有效, 并使用扩展结构体
        stInStartFind.emObjectType = NetSDKLib.EM_OBJECT_TYPE.EM_OBJECT_TYPE_FACE;
        // 图片信息
        if (memory != null && nPicLen > 0) {
            System.out.println("detect image");
            String picPath = "D:\\tool\\work\\4.jpg";
            byte[] picBuf = ToolKits.readPictureToByteArray(picPath);
//            ToolKits.savePicture(picBuf, "D:\\tool\\work\\wcnm.jpg");
            stInStartFind.pBuffer = new Memory(picBuf.length);
            stInStartFind.pBuffer.write(0,picBuf,0,picBuf.length);
            stInStartFind.nBufferLen = nPicLen;
            stInStartFind.bPersonEx2Enable = 1;    // 人员信息查询条件是否有效, 并使用扩展结构体
            stInStartFind.stPersonInfoEx2.nFacePicNumEx = 1;
            stInStartFind.stPersonInfoEx2.stuFacePicInfoEx[0].dwOffSet = 0;
            stInStartFind.stPersonInfoEx2.stuFacePicInfoEx[0].dwFileLenth = nPicLen;
//            stInStartFind.stPersonInfoEx2.bPersonExEnable = 1;
//            stInStartFind.stPersonInfoEx2.nFacePicNumEx = 1;
//            stInStartFind.stPersonInfoEx2.stPersonInfoEx.
//            stInStartFind.stPersonInfoEx2.stPersonInfoEx.szFacePicInfo[0].dwOffSet = 0;
//            stInStartFind.stPersonInfoEx2.stPersonInfoEx.szFacePicInfo[0].dwFileLenth = nPicLen;
        }

        // 相似度
        if (!similary.equals("")) {
            stInStartFind.stMatchOptions.nSimilarity = Integer.parseInt(similary);
            stInStartFind.stMatchOptions.nMaxCandidate = 5;
        }

        stInStartFind.stFilterInfo.nGroupIdNum = 0;
        stInStartFind.stFilterInfo.nRangeNum = 1;
        stInStartFind.stFilterInfo.szRange[0] = NetSDKLib.EM_FACE_DB_TYPE.NET_FACE_DB_TYPE_HISTORY;
        stInStartFind.stFilterInfo.stStartTime.dwYear = Integer.parseInt(startTimeStr[0]);
        stInStartFind.stFilterInfo.stStartTime.dwMonth = Integer.parseInt(startTimeStr[1]);
        stInStartFind.stFilterInfo.stStartTime.dwDay = Integer.parseInt(startTimeStr[2]);
        stInStartFind.stFilterInfo.stEndTime.dwYear = Integer.parseInt(endTimeStr[0]);
        stInStartFind.stFilterInfo.stEndTime.dwMonth = Integer.parseInt(endTimeStr[1]);
        stInStartFind.stFilterInfo.stEndTime.dwDay = Integer.parseInt(endTimeStr[2]);
        stInStartFind.stFilterInfo.emFaceType = NetSDKLib.EM_FACERECOGNITION_FACE_TYPE.EM_FACERECOGNITION_FACE_TYPE_ALL;

        //让设备根据查询条件整理结果集
        NET_OUT_STARTMULTIFIND_FACERECONGNITION_EX stOutParam = new NET_OUT_STARTMULTIFIND_FACERECONGNITION_EX();
        stInStartFind.write();
        stOutParam.write();
        if (netsdkApi.CLIENT_StartMultiFindFaceRecognitionEx(loginHandle, stInStartFind.getPointer(), stOutParam.getPointer(), 2000)) {
            stOutParam.read();
            System.out.println("CLIENT_StartMultiFindFaceRecognitionEx success, count = " + stOutParam.nTotalCount);
            findHandle = stOutParam.lFindHandle;
            if(stOutParam.nTotalCount > 0){
                doFindSearchByPictureEx(findHandle, 10);
            }
            if (stOutParam.nTotalCount == -1) {   // -1表示总条数未生成,要推迟获取, 使用CLIENT_AttachFaceFindState接口状态
                nToken = stOutParam.nToken;
                // 入参
                NET_IN_MULTIFACE_DETECT_STATE pstInParam = new NET_IN_MULTIFACE_DETECT_STATE();
                pstInParam.nTokensNum = 1;
                pstInParam.nTokens[0] = nToken;  // 查询令牌
                pstInParam.cbMultiFaceDetectState = new MultiFaceDetectState();

                // 出参
                NET_OUT_MULTIFACE_DETECT_STATE pstOutParam = new NET_OUT_MULTIFACE_DETECT_STATE();

                pstInParam.write();
                attachFaceHandle = netsdkApi.CLIENT_AttachDetectMultiFaceState(loginHandle, pstInParam.getPointer(), pstOutParam.getPointer(), 4000);
                pstInParam.read();
                if (attachFaceHandle.longValue() != 0) {
                    System.out.println("AttachFaceFindState Succeed!");
                } else {
                    System.out.println(
                            "AttachFaceFindState Failed, Error:" + ToolKits.getErrorCode());
                    return;
                }

                NET_IN_FACE_RECOGNITION_DETECT_MULTI_FACE_INFO stIn = new NET_IN_FACE_RECOGNITION_DETECT_MULTI_FACE_INFO();
                stIn.nBigPicNum = 1;
                String picPath = "D:\\tool\\work\\4.jpg";
                byte[] picBuf = ToolKits.readPictureToByteArray(picPath);
                stIn.stuBigPicInfo[0].dwFileLenth = picBuf.length;
                stIn.nBufferLen = picBuf.length;
                stIn.pBuffer = new Memory(picBuf.length);
                stIn.pBuffer.write(0, picBuf, 0, picBuf.length);
                stIn.nToken = nToken;
                NET_OUT_FACE_RECOGNITION_DETECT_MULTI_FACE_INFO stOut = new NET_OUT_FACE_RECOGNITION_DETECT_MULTI_FACE_INFO();
                stIn.write();
                stOut.write();
                boolean bRet = netsdkApi.CLIENT_FaceRecognitionDetectMultiFace(loginHandle, stIn.getPointer(), stOut.getPointer(), 3000);
                if (bRet) {
                    System.out.println("CLIENT_FaceRecognitionDetectMultiFace success");
                } else {
                    System.out.println("CLIENT_FaceRecognitionDetectMultiFace failed");
                    System.out.println("error = " + ToolKits.getErrorCode());
                }
            }
        } else {
            System.out.println(
                    "CLIENT_StartMultiFindFaceRecognitionEx Failed, Error:" + ToolKits.getErrorCode());
        }
    }

    public void tryMethod(){
        String picPath = "D:\\tool\\work\\4.jpg";
        byte[] picBuf = ToolKits.readPictureToByteArray(picPath);
        Memory memory = new Memory(picBuf.length);
        memory.write(0,picBuf,0,picBuf.length);
        searchByPictureMultiVer("2022-11-20","2022-11-27",0,"10",memory,picBuf.length);
//        doFindSearchByPictureEx(loginHandle, 10);
    }

    public void RunTest() {
        System.out.println("Run Test");
        CaseMenu menu = new CaseMenu();
        menu.addItem((new CaseMenu.Item(this, "tryMethod", "tryMethod")));
        menu.run();
    }

    public static void main(String[] args) {
        MultiFaceDemo multiFaceDemo = new MultiFaceDemo();
        InitTest("172.25.239.136", 37777, "admin", "Admin123");
        multiFaceDemo.RunTest();
        LoginOut();
    }
}
